package cloudeval.spec

import cn.edu.neu.vmmigeval.cloud.config.CloudletRegistry
import cn.edu.neu.vmmigeval.cloud.entity.Cloudlet
import cn.edu.neu.vmmigeval.cloud.entity.DataCenter
import cn.edu.neu.vmmigeval.cloud.entity.DataCenterBroker
import cn.edu.neu.vmmigeval.cloud.entity.UtilizationModel
import cn.edu.neu.vmmigeval.cloud.policy.WorkloadModel

import java.util.concurrent.atomic.AtomicInteger

/**
 * The workload specification.
 *
 * @author yfwz100
 */
class WorkloadSpec {

    class CloudletSpec {

        private UtilizationModel cpuModel, ramModel, diskModel, bwModel
        private long cloudletLength

        private static final AtomicInteger idGenerator = new AtomicInteger()

        void cpu(UtilizationModel model) {
            cpuModel = model
        }

        void ram(UtilizationModel model) {
            ramModel = model
        }

        void disk(UtilizationModel model) {
            diskModel = model
        }

        void bandwidth(UtilizationModel model) {
            bwModel = model
        }

        void length(long length) {
            cloudletLength = length
        }

        Cloudlet createCloudlet(int start) {
            new Cloudlet(
                    idGenerator.incrementAndGet(),
                    cloudletLength,
                    start,
                    cpuModel, ramModel, bwModel, diskModel
            )
        }
    }

    class SimpleWorkloadModel implements WorkloadModel {

        @Override
        void addCloudlets(int clock, DataCenterBroker broker, DataCenter center) {
            List<Cloudlet> cloudlets = new ArrayList<Cloudlet>();

            cloudletMap.each { clr, size ->
                int flag = 0
                while (flag < size) {
                    Cloudlet cloudlet = clr.createCloudlet(clock)

                    /**
                     * 该方法还没有完成
                     */

                    boolean result = broker.getCloudletAllocation().allocateVmForCloudlet(broker.getVms(), cloudlet);
                    try {
                        if (!result) {
                            throw new Exception("++任务无法分配到虚拟机");
                        }
//                        else{
//                            System.out.println("已经为云任务分配到虚拟机！");
//                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    cloudlets.add(cloudlet);
                    flag++;
                }
            }
            broker.getCloudlets().addAll(cloudlets);
        }
    }

    private Map<CloudletSpec, Integer> cloudletMap = new HashMap<>()

    public Map<CloudletSpec, Integer> getCloudletMap() {
        return cloudletMap
    }

    CloudletSpec cloudlet(int size, @DelegatesTo(CloudletSpec) Closure closure) {
        def spec = new CloudletSpec()
        def code = closure.rehydrate(spec, this, this)
        code.resolveStrategy = Closure.DELEGATE_ONLY
        code()

        cloudletMap[spec] = size

        return spec
    }

    WorkloadModel createWorkloadModel() {
        new SimpleWorkloadModel()
    }
}
